import sys
import time
import queue
import threading


class Logger:
    def __init__(self, interface) -> None:
        self.logger_name = ""
        self.__io = sys.stdout
        self.__buffer = ""
        self.__queue_buffer = queue.Queue()
        self.__queue_max = 32
        self.__format_string = "[{time}] [{infunc}] [{level}] | {text}"
        self.__lock = threading.Lock()

    def __setlogio(self, io):
        self.__io = io
        return self.__io

    def __write(self, text: str):
        _ = self.__io.write(text)
        self.__io.flush()
        return _

    def __flush(self):
        self.__queue_buffer.queue.clear()
    
    def __set_buffer(self, bfsize: int):
        self.__queue_max = bfsize

    def __out(self, wait=False):
        if wait:
            self.__buffer = self.__queue_buffer.get(wait)
        else:
            try:
                self.__buffer = self.__queue_buffer.get(wait)
            except queue.Empty:
                self.__buffer = [
                    "WARNING", "there is no logging waiting output", self.info.__module__]
        lvl = self.__buffer[0]
        txt = self.__buffer[1]
        inf = self.__buffer[2]
        self.__write(self.__format_string.format(time=time.strftime(
            r"%Y-%m-%d %H:%M:%S"), level=lvl, text=txt, infunc=inf, loggername = self.logger_name) + "\n")

    def __out_flush(self):
        self.__lock.acquire()
        while not self.__queue_buffer.empty():
            self.__out()
        self.__flush()
        self.__lock.release()

    def __set_format(self, format):
        self.__format_string = format
        return self.__format_string

    def __info(self, text, infunc="<anonymous>"):
        self.__lock.acquire()
        if self.__queue_buffer.qsize() >= self.__queue_max:
            print("WARNING!!! Memory used too large, program is clearing all items in queue.If you want to save logging, please run the whileouting function or out function")
            threading.Thread(target=self.__out_flush).start()
        try:
            self.__queue_buffer.put(
                ["INFO", text, infunc.__module__ + "." + infunc.__name__])
        except AttributeError:
            if type(infunc) == str:
                self.__queue_buffer.put(["INFO", text, infunc])
            else:
                self.__queue_buffer.put(
                    ["WARNING", "the value of infunc variable is not a callback function or string.", self.info.__module__])
                self.__queue_buffer.put(["INFO", text, "<unknown>"])
        self.__lock.release()

    def __warning(self, text, infunc="<anonymous>"):
        self.__lock.acquire()
        if self.__queue_buffer.qsize() >= self.__queue_max:
            print("WARNING!!! Memory used too large, program is clearing all items in queue.If you want to save logging, please run the whileouting function or out function")
            threading.Thread(target=self.__out_flush).start()
        try:
            self.__queue_buffer.put(
                ["WARNING", text, infunc.__module__ + "." + infunc.__name__])
        except AttributeError:
            if type(infunc) == str:
                self.__queue_buffer.put(["WARNING", text, infunc])
            else:
                self.__queue_buffer.put(
                    ["WARNING", "the value of infunc variable is not a callback function or string.", self.info.__module__])
                self.__queue_buffer.put(["WARNING", text, "<unknown>"])
        self.__lock.release()

    def getLogger(self, name):
        self.logger_name = name
        self.info = self.__info
        self.warning = self.__warning
        self.out = self.__out
        self.setFormat = self.__set_format
        self.setIO = self.__setlogio
        # self.mp_mode = self.__mp_mode
        self.out_flush = self.__out_flush
        self.setBuffer = self.__set_buffer
        return self